import numpy as np

def sigmod(input):
    output = 1 if input > 0 else 0
    return output

class Perceptron(object):
    def __init__(self, width):
        # +1 for bias
        self.w = np.random.uniform(-1, 1, width+1)
    
    def predict(self, input):
        # 加上bias的输入量1
        return sigmod(np.dot(self.w, self.convert_input(input)))

    def convert_input(self, input):
        return np.array(list(input) + [1])
    
    def __str__(self):
        return "weights: %s\nbias: %s\n" %(self.w[:-1], self.w[-1])


    def _update_weight(self, input, predict_res, label, rate):
        print("update_weight predict=%s, label=%s, rate=%s" %(predict_res, label, rate))
        # 公式delta_w = rate*(t-y)*x --> x*delta_w = rate*(t-y)*x^2, 所以如果t>y 那么(w+delta_w)*x > w*x ,就会使结果y更靠近t, 反正依然
        delta_w = self.convert_input(input)*rate*(label-predict_res)
        self.w += delta_w

    def train(self, inputs, labels, rate, iteration):
        for i in range(iteration):
            print("train iteration %s" %(i+1))
            for j, input in enumerate(inputs):
                label = labels[j]
                self._one_iteration_train(input, label, rate)
            print("after %s train: %s" %(i+1, self))
    
    def _one_iteration_train(self, input, label, rate):
        result = self.predict(input)
        self._update_weight(input, result, label, rate)


# 训练and操作符
def train_and_op():
    inputs = ((0, 0), (1, 0), (0, 1), (1,1))
    labels = (0, 0, 0, 1)
    rate = 0.1 # 学习率
    iteration = 10 # 
    and_perceptron  = Perceptron(2)
    and_perceptron.train(inputs, labels, rate, iteration)

    print("and_perceptron:")
    for input in inputs:
        print("input:%s npredict:%s" %(input, and_perceptron.predict(input)))


# 训练or操作符
def train_or_op():
    inputs = ((0, 0), (1, 0), (0, 1), (1,1))
    labels = (0, 1, 1, 1)
    rate = 0.1 # 学习率
    iteration = 10 # 
    or_perceptron  = Perceptron(2)
    or_perceptron.train(inputs, labels, rate, iteration)

    print("or_perceptron:")
    for input in inputs:
        print("input:%s npredict:%s" %(input, or_perceptron.predict(input)))


if __name__ == "__main__":
    train_and_op()
    train_or_op()

